﻿#include "websocket_client.hpp"
#include "asio.hpp"
#include "p2pms_log.hpp"
#include <functional>

using namespace p2pms;
using namespace std::placeholders;

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
WebSocketClient::~WebSocketClient()
{
	Stop();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool WebSocketClient::Init(IWebSocketHandler* handler)
{
	if (!handler) {
		LOG_DBG("invalid handler");
		return true;
	}
	m_handler = handler;

	// 设置日志级别
	m_client.clear_access_channels(websocketpp::log::alevel::all);
	m_client.set_error_channels(websocketpp::log::elevel::all);
	m_client.set_access_channels(websocketpp::log::alevel::app);

	// 绑定回调函数
	m_client.set_open_handler(std::bind(&WebSocketClient::OnOpen, this, _1));
	m_client.set_message_handler(std::bind(&WebSocketClient::OnMessage, this, _1, _2));
	m_client.set_close_handler(std::bind(&WebSocketClient::OnClose, this, _1));

	// 初始化 ASIO
	m_client.init_asio(&m_ioc);

	return true;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool WebSocketClient::Start(const std::string& uri)
{
	if (uri.empty()) {
		LOG_ERR("empty uri");
		return false;
	}
	m_uri = uri;

	// 连接到服务器
	websocketpp::lib::error_code ec;
	WsClient::connection_ptr con = m_client.get_connection(m_uri, ec);
	if (ec) {
		LOG_ERR("connection error:{}", ec.message());
		return false;
	}

	m_client.connect(con);

	// 启动一个新线程来运行 I/O 上下文，防止主线程阻塞
	m_io_thread = std::thread([this]() { m_ioc.run(); });

	return true;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void WebSocketClient::Stop()
{
	// 停止 I/O 上下文，这将导致 run() 调用返回
	if (!m_ioc.stopped()) {
		m_ioc.stop();
	}

	// 等待 I/O 线程结束
	if (m_io_thread.joinable()) {
		m_io_thread.join();
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool WebSocketClient::SendMsg(const std::string& msg)
{
	websocketpp::connection_hdl hdl_copy;
	{
		std::lock_guard<std::mutex> lock(m_hdl_mutex);
		hdl_copy = m_conn_hdl;
	}
	
	LOG_INF("Sending messsage: {}", msg);

	if (hdl_copy.lock()) {
		websocketpp::lib::error_code ec;
		m_client.send(hdl_copy, msg, websocketpp::frame::opcode::text, ec);
		if (ec) {
			LOG_ERR("SendMessage error:{}", ec.message());
			return false;
		}
		return true;
	} else {
		LOG_ERR("SendMessage error: no active connection.");
		return false;
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void WebSocketClient::OnOpen(websocketpp::connection_hdl hdl)
{
	LOG_INF("connection opened.")

	{
		std::lock_guard<std::mutex> lock(m_hdl_mutex);
		m_conn_hdl = hdl;
	}

	if (m_handler) m_handler->OnConnected();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void WebSocketClient::OnMessage(websocketpp::connection_hdl hdl, WsClient::message_ptr msg)
{
	LOG_INF("received message: {}", msg->get_payload());

	if (m_handler) m_handler->OnMessage(msg->get_payload());
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void WebSocketClient::OnClose(websocketpp::connection_hdl hdl)
{
	LOG_INF("connection closed");

	if (m_handler) m_handler->OnDisconnected();
}